package starter.gate.netty;

import static com.bowlong.tool.Lib2.e2s;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import starter.game.netty.contxt.SvcContext;
import starter.game.service.impl.GameServiceImp;

import com.bowlong.bio3.B3InputStream;
import com.bowlong.lang.PStr;
import com.bowlong.util.Log;
import com.bowlong.util.NewMap;

@SuppressWarnings({ "rawtypes" })
public class GateTcpHandler extends ChannelInboundHandlerAdapter {
	public static GateTcpHandler INS = new GateTcpHandler();

	static final AttributeKey<SvcContext> STATE = AttributeKey.valueOf("c");
	static final Map<Integer, SvcContext> chns = new ConcurrentHashMap<>();
	public static final GameServiceImp service = new GameServiceImp();
	static boolean isShutdown = false;

	@Override
	public void channelActive(ChannelHandlerContext chc) throws Exception {
	}

	@Override
	public void channelInactive(ChannelHandlerContext chc) throws Exception {
		close(chc);
	}

	@Override
	public void channelRead(final ChannelHandlerContext chc, Object msg)
			throws Exception {
		// Log.p("--------------------channelRead--------------------");
		if (isShutdown)
			return;

		try {
			ByteBuf buf = (ByteBuf) msg;
			final ByteBufInputStream content = new ByteBufInputStream(buf);
			int inLen = 0;
			int outLen = 0;

			SvcContext ctx = null;
			try {
				inLen = content.available();
				long t1 = System.currentTimeMillis();
				Map map = B3InputStream.readMap(content);
				NewMap params = NewMap.create(map);
				// int cmd = params.getInt(0);

				// 取得缓存对象
				ctx = chc.attr(STATE).get();
				if (ctx == null) { // 新连接
					ctx = new SvcContext(chc, inLen, params);
					chc.attr(STATE).set(ctx);
				} else { // 更改请求信息
					ctx.init(inLen, params);
				}

				if (ctx.uid > 0 && !chns.containsKey(ctx.uid))
					chns.put(ctx.sid, ctx);

				outLen = service.disp(ctx, params);
				String minfo = service._params(params);
				long t2 = System.currentTimeMillis();
				long time = t2 - t1;

				// if (cmd != 200896764) // 心跳数据不打印
				Log.info(PStr.b("Time:", time, " in:", inLen, " out:", outLen,
						" uid:", ctx.uid, " name:", ctx.name(), "\n").e(minfo));
				// Log.info(PStr.b(methodName,
				// " : Time : ").e(time));
			} catch (Exception e1) {
				if (ctx != null)
					remove(ctx.uid);
				else
					chc.close();

				Log.error(e1.getMessage(), e1);
			}
		} catch (Exception e) {
			Log.error(e);
			chc.close();
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext chc, Throwable cause)
			throws Exception {
		Log.p(e2s(cause));
		close(chc);
	}

	public static void closeAll() {
		try {
			Set<Entry<Integer, SvcContext>> ens = chns.entrySet();
			for (Map.Entry<Integer, SvcContext> tcp : ens) {
				try {
					SvcContext chn = tcp.getValue();
					chn.close();
				} catch (Exception e) {
				}
			}
		} catch (Exception e) {
			Log.info(Log.e2s(e));
		}
	}

	public static SvcContext getTcpByYhid(int yhid) {
		return chns.get(yhid);
	}

	public static int count() {
		return chns.size();
	}

	public static List<SvcContext> tcps() {
		return new ArrayList<SvcContext>(chns.values());
	}

	public static void close(ChannelHandlerContext chc) {
		SvcContext ctx = chc.attr(STATE).get();
		if (ctx != null)
			ctx.close();

		chc.close();
	}

	public static void remove(int uid) {
		chns.remove(uid);
	}

	public static boolean isOnline(int yhid) {
		return chns.containsKey(yhid);
	}
}